import pygame
import pygame.font
from pygame.locals import *

class shipSprite(pygame.sprite.Sprite):
    

    
    def __init__(self, image, position):
        pygame.sprite.Sprite.__init__(self)
        
        self.src_image = pygame.image.load(image)
        self.position = position
        self.image = self.src_image
        self.rect = self.image.get_rect()
        self.rect.center = self.position
    
    def update(self):
        #To be deleted?
        #self.rect = self.image.get_rect()
        self.rect.center = self.position

class shooter():
    shots = []
    shotsG = []
    speed = 20
    
    def __init__(self): 
        self.image = pygame.image.load("bullet.png")
        self.sound = pygame.mixer.Sound("bullet_shoot_fast.wav")
    
    def newBullet(self, (x, y)):
        if len(self.shots) < 3:
            self.shotsG.append(pygame.sprite.RenderPlain())
            self.shots.append(pygame.sprite.Sprite(self.shotsG[-1]))
            self.shots[-1].image = self.image
            self.shots[-1].rect = self.shots[-1].image.get_rect()
            self.shots[-1].rect.center = (x,y)
            self.sound.play()
            
    def updateBullet(self, screen):
        index = 0
        while index < len(self.shots):
            self.shots[index].rect.center = (self.shots[index].rect.center[0], self.shots[index].rect.center[1] - self.speed)
            if self.shots[index].rect.center[1] < 0:
                del(self.shots[index])
                index -= 1
            index += 1
                
        if len(self.shots) == 0:
            self.shotsG = []
            
        #Works over all the shot groups, and if it has a sprite, it gets rendered, otherwise it goes
        #in the bit bucket
        #Uses a while loop because you're incrementing over the list you're editing it, so a for
        #chokes after you edit the list and change what it expects to be where
        i = 0
        while i < len(self.shotsG):
            if len(self.shotsG[i].sprites()) == 0:
                del(self.shotsG[i])
                    
            else:
                self.shotsG[i].draw(screen)
            i += 1
            
    def returnPaths(self):
        toRet = []
        for i in self.shots:
            toRet.append((i.rect.center[0], i.rect.center[1]))
        return toRet
        
class enemyShip(pygame.sprite.Sprite):
    impendingCollision = False
    dodging = 0
    speed = 40
    step = 4
    move = 0
    counter = 0

    
    
    def __init__(self, image, position):
        pygame.sprite.Sprite.__init__(self)

        self.sound = pygame.mixer.Sound("alien_short.wav")
        self.sound.set_volume(.6)
        self.sound.play(-1)
        #self.src_image = pygame.image.load(image)
        self.images = []
        for i in ["enemy1.png", "enemy2.png", "enemy3.png", "enemy4.png"]:
            self.images.append(pygame.image.load(i))
        self.position = position
        #self.image = self.src_image
        self.image = self.images[0]
        self.rect = self.image.get_rect()
        self.rect.center = self.position
    
    def update(self):
        from math import floor
        self.counter += .2
        if self.counter >= 4:
            self.counter = 0
        self.image = self.images[int(floor(self.counter))]
        return
        #self.rect.center = self.position
    
    def impending(self, coords):
        self.impendingCollision = False
        for i in coords:
            if (abs(i[0] - self.rect.center[0]) < (self.rect.width / 2) and ((i[1] - self.rect.center[1]) <  200)):
                self.impendingCollision = True
                break
        
#        if self.impendingCollision:
#            avg = 0
#            for i in coords:
#                avg += i[0]
#                print avg
#            avg /= len(coords)
#            print avg
#            avg -= self.rect.center[0]
#            print avg
#            
#            #To prevent div/0
#            if avg == 0:
#                avg = 1
#            
#            self.dodge = (avg) / abs(avg)
#            print self.dodge
#            print self.dodge
#            self.position = (self.position[0] + self.dodge * self.speed, self.position[1])

        
    
    def getImpending(self):
       return self.impendingCollision
        

    
class shipCount():
    ships = []
    shipGroup = pygame.sprite.RenderPlain()
    
    def __init__(self, image, position):
        for i in range(0,3):
            self.ships.append(pygame.sprite.Sprite())
            self.ships[-1].image = pygame.image.load(image)
            self.ships[-1].position =  (position[0] +  35 * i, position[1])
            self.ships[-1].rect = self.ships[-i].image.get_rect()
            self.ships[-1].rect.center =  self.ships[-1].position
            self.shipGroup.add(self.ships[-1])
            
    
    def draw(self):
        self.shipGroup.draw(screen)
    
    def removeShip(self):

        if(len(self.ships) > 0):
            self.ships[-1].kill()
            del(self.ships[-1])
            self.shipGroup.draw(screen)
            pygame.display.flip()

class Bomber():

    speed = 8
     
    def __init__(self, image, position):
        self.bombG = pygame.sprite.RenderPlain()
        self.bomb = pygame.sprite.Sprite(self.bombG)
        self.bomb.image = pygame.image.load(image)
        self.bomb.rect = self.bomb.image.get_rect()
        self.bomb.rect.center = position
 
    def update(self, shipPos):
        from math import sqrt
        #If they run, it runs faster!
        self.speed *= 1.01
        dx = self.bomb.rect.center[0] - shipPos[0]
        #if(sWidth - dx < dx):
        #    dx = -1 *  sWidth-dx
        dy = self.bomb.rect.center[1] - shipPos[1]
        magnitude = sqrt((dx ** 2) + (dy ** 2))
        dx = dx * self.speed / magnitude
        dy = dy * self.speed / magnitude
        
        #if(self.bomb.rect.center[0] - dx < 0):
         #   dx -= sWidth
        #if(self.bomb.rect.center[0] - dx >  sWidth):
        #    dx +=  sWidth
        self.bomb.rect.center = (self.bomb.rect.center[0] - dx, self.bomb.rect.center[1] - dy)
        
def newBomb(position):
    from random import random
    if(random() < .005):
        return Bomber("bomb.png", position)
    else:
        return None
    

def introScreen():
    #Initialize the fonter thing
    font = pygame.font.Font("digistrip.ttf", 18)
    
    #The strings to be rendered
    #Text is an array so it can be programmatically displayed
    title = "FUTILITY"
    text = ["You are located just below a maddening alien ", "who whirls just to bother you. Your mission is ", "to destroy him; unfortunately, this is impossible,  ", "as he cannot be hit. But you must try! Eventually,", "he will tire of your bothersome pranks which ", "interrupt his whirling, and destroy you with","an antimatter bomb.","", "You have ten years to accomplish your mission."]
    
    
    #Creates anonymous text surfaces (with font.render()) and immediately blit them
    #to draw the text
    
    screen.blit(font.render(title, 1, (255, 255, 255)), (300, 50))
    

    
    for i in range(0, len(text)):
        screen.blit(font.render(text[i], 1, (255, 255, 255)), (50, 100+(i*20)))
        #Make the text display slowly
        clock.tick(9)        
        pygame.display.flip()
    
    #Make it so!
    pygame.display.flip()
    
    #Wait for a key to be pressed
    while 1:
        event = pygame.event.wait()
        #If it's the enter key, return to the main
        if ((event.type == KEYDOWN) and (event.key == K_ESCAPE)):
            from sys import exit
            exit(0)
        elif (event.type == KEYDOWN):
            return
        
    
def drawHUD(score, years, ships):
    screen.blit(score, (10,10))
    screen.blit(years, (520, 10))
    ships.draw()


def main():
    from random import randint
    font = pygame.font.Font("digistrip.ttf", 20)
    
    score = font.render("Score: 0", 1, (255, 255, 255))
    years = font.render("Years: 10", 1, (255, 255, 255))
    ships = shipCount("ship.png", (20,50))
    shipSpeed = 10

    leftDown = False
    rightDown = False
    
    
    #TODO: CLEAN THIS SHIT UP
    shipGroup = pygame.sprite.RenderPlain()
    ship = pygame.sprite.Sprite(shipGroup)
    ship.image = pygame.image.load("ship.png")
    ship.position = (320, 460)
    ship.rect = ship.image.get_rect()
    ship.rect.center = ship.position

    
    alien = enemyShip("enemy.png", (320, 30))
    alienG = pygame.sprite.RenderPlain(alien)

    shot = shooter()
    
    shieldG = pygame.sprite.RenderPlain()
    shield = pygame.sprite.Sprite(shieldG)
    shield.image = pygame.image.load("shield.png")
    shield.position = (alien.position)
    shield.rect = shield.image.get_rect()
    shield.rect.center = shield.position

    fallingSound = pygame.mixer.Sound("bomb_fall.wav")
    explosionSound = pygame.mixer.Sound("bomb_explode.wav")
    
    quit = False
    pause = False
    shieldUp = False
    
    
    alien.move = 0
    
    #initial empty value
    kill = None
    
    #Number of frames to skip when dying
    shipTimer = 0
    #Number of frames to skip without dropping a bomb (30 frames/sec)
    bombTimer = 300
    
    while not quit:
        clock.tick(30)
        
        if pause:
            font = pygame.font.Font("digistrip.ttf", 18)
            paused = font.render("PAUSED", 1, (255, 255, 255))
            screen.blit(paused, (275, 200))
            pygame.display.flip()
            event = pygame.event.wait()
            while((event.key != K_PAUSE) or (event.type == KEYUP)):
                event = pygame.event.wait()
            pause = False
                
        
                
        screen.fill((0,0,0))
        drawHUD(score, years, ships)
        if shipTimer == 0:
            shipGroup.draw(screen)
        else:
            shipTimer -= 1
            if shipTimer == 0:
                #If shipTimer just got ot 0
                #(The player is about to respawn)
                ship.position = (320, 460)
        
        if alien.move:
            alien.rect.center = (alien.rect.center[0] + alien.step * alien.move/abs(alien.move), alien.rect.center[1])
            alien.move -= alien.step * alien.move/abs(alien.move)
        
        if alien.getImpending():

            if len(shot.shots) == 1 and not shieldUp:

                
                if (alien.rect.center[0] + alien.move < 200) or (alien.rect.center[0] + alien.move> 450):
                    alien.move *= -1
                    #alien.rect.center = (alien.rect.center[0] + alien.speed, alien.rect.center[1])
                else:
                    
                    if alien.move == 0:
                        #dir = ((ship.rect.center[0]/alien.rect.center[0])  % 2)
                        dir = randint(0,1)
                    
                    if dir == 0:
                        dir = -1
                    
                    if alien.move == 0:
                        alien.move += alien.speed * dir    
                    #alien.rect.center = (alien.rect.center[0] - dir * alien.speed, alien.rect.center[1])
                    if (alien.rect.center[0] + alien.move < 200) or (alien.rect.center[0] + alien.move> 450):
                        alien.move *= -1
                
            else:
                if alien.move == 0:
                    shield.rect.center = alien.rect.center
                    shieldG.draw(screen)
                    shieldUp = True
            for i in shot.shotsG:
                #If a shot collides with shield, kill it (remove it from groups)
                #TODO: Optimize so it doesn't have to use the "dokill = True" option
                pygame.sprite.spritecollide(shield, i, True)
#                if (pygame.sprite.spritecollide(shield, i, True)):
                    #if(kill == None):

                    
        else:
            if((kill == None) and (shipTimer == 0)):
                if(bombTimer == 0):
                    kill = newBomb(alien.rect.center)
                else:
                    bombTimer -= 1
            if alien.move == 0:
                shieldUp = False
                
        
        
        shot.updateBullet(screen)
        alien.impending(shot.returnPaths())
        alien.update()
        alienG.draw(screen)

        
        if kill != None:
            if fallingSound.get_num_channels() == 0:
                fallingSound.play()
            kill.update(ship.position)
            kill.bombG.draw(screen)
            if (pygame.sprite.spritecollide(ship, kill.bombG, True)):
                explosionSound.play()
                fallingSound.stop()
                kill.update(ship.position)
                #pygame.display.flip() NOT NEEDED?
                kill = None
                shipCount.removeShip(ships)
                shipTimer = 60
                bombTimer = 300
                
            
                
        
        #print shot.returnPaths()

        pygame.display.flip()


    
        
        for event in pygame.event.get():
            #print event
            if event.type == QUIT:
                quit = True
            
            if not hasattr(event, 'key'): continue
            
            if (event.key == K_ESCAPE):
                quit = True
            elif shipTimer == 0 and (event.key == K_SPACE and event.type == KEYDOWN):
                shot.newBullet(ship.position)
            elif event.key == K_LEFT:
                if event.type == KEYDOWN:
                    leftDown = True
                elif event.type == KEYUP:
                    leftDown = False
            elif event.key == K_RIGHT:
                if event.type == KEYDOWN:
                    rightDown = True
                elif event.type == KEYUP:
                    rightDown = False
            elif ( (event.key == K_PAUSE ) and (event.type == KEYDOWN)):
                pause = True
                
                    
                
        ship.position = (ship.position[0] - (leftDown * shipSpeed) + (rightDown * shipSpeed), ship.position[1])
        if (ship.position[0] > sWidth):
            ship.position = (0, ship.position[1])
        elif (ship.position[0] < 0):
            ship.position = (sWidth, ship.position[1])
        ship.rect.center = ship.position
        if len(ships.ships) == 0:
            gameOver(alien, alienG, score, years, ships)
            quit = True

def gameOver(alien, alienG, score, years, ships):
    
    font = pygame.font.Font("digistrip.ttf", 18)
    itsOver = font.render("GAME OVER", 1, (255, 255, 255))
    
    #pygame.display.flip()
    
    #Wait for a key to be pressed
    while 1:
        if((True) and alien.rect.center[0] < sWidth + 25):
            clock.tick(30)  
            screen.fill((0,0,0))
            drawHUD(score, years, ships)
            alien.rect.center = (alien.rect.center[0] + alien.speed * .25, alien.rect.center[1])
            alien.update()
            alienG.draw(screen)
            screen.blit(itsOver, (275, 200))
            pygame.display.flip()
        else:
            alien.sound.stop()
            event = pygame.event.wait()
            #press any key to continue
            if (event.type == KEYDOWN):
                return
            
sWidth = 640
sHeight = 480
screen = pygame.display.set_mode ((sWidth, sHeight))
rect = screen.get_rect()
pygame.init()
clock = pygame.time.Clock()

#ship = shipSprite("./workspace/FutFor/src/ship.png", rect.center)
#shipG = pygame.sprite.RenderPlain(ship)
#
#shipG.draw(screen)

introScreen()

main()

